class Compiler {
    constructor(vm) {
        this.vm = vm
        this.el = vm.$el

        // 构造函数中执行编译
        this.compile(this.el)
    }

    compile(el) {
        if (!el) {
            return
        }
        const children = el.childNodes
        Array.from(children).forEach(node => {
            if (this.isElementNode(node)) {
                this.compileElement(node)
            } else if (this.isTextNode(node)) {
                this.compileText(node)
            }

            // 递归处理node下面的子节点
            if (node.childNodes && node.childNodes.length) {
                this.compile(node)
            }
        })
    }

    compileElement(node) {
        const directives = this.vm.$options.directives
        Array.from(node.attributes).forEach(attr => {
            // 判断是否是指令
            let attrName = attr.name
            if (this.isDirective(attrName)) {
                // v-text --> text
                // 获取指令的相关数据
                let attrNames = attrName.substr(2).split(':')
                let name = attrNames[0]
                let arg = attrNames[1]
                let key = attr.value

                // 获取注册的指令并执行
                if (directives[name]) {
                    node.vm = this.vm
                    // 执行指令绑定
                    directives[name].bind(node, {
                        name: name,
                        value: this.vm[key],
                        argument: arg,
                        expression: key
                    })

                    new Watcher(this.vm, key, () => {
                        directives[name].update(node, {
                            name: name,
                            value: this.vm[key],
                            argument: arg,
                            expression: key
                        })
                    })
                }
            }
        })
    }

    compileText(node) {
        // 利用正则表达式匹配插值表达式
        let reg = /\{\{(.+?)\}\}/
        const value = node.textContent
        if (reg.test(value)) {
            let key = RegExp.$1.trim()
            node.textContent = value.replace(reg, this.vm[key])

            new Watcher(this.vm, key, () => {
                node.textContent = this.vm[key]
            })
        }
    }

    // 判断元素属性是否是指令，简化vue原来逻辑，现在默认只有v-开头的属性是指令
    isDirective(attrName) {
        return attrName.startsWith('v-')
    }
    // 判断节点是否是文本节点
    isTextNode(node) {
        return node.nodeType === 3
    }
    // 判断节点是否是元素节点
    isElementNode(node) {
        return node.nodeType === 1
    }
}